Repository navigation
app: serve remote views on GET /remote - #730
Merged
Merged
Conversation
foxnne
force-pushed
the
app/remote-view-host
branch
from
October 21, 2026 19:09
95e3fdb to
813ee74
Compare
A client upgrades a connection on the control socket (Upgrade: fizzy-remote-view/1) and speaks the sdk/remote protocol: it opens views, sends pointer, key and text input, and asks for frames. Each view is a RemoteViewHost, a ViewHost the OS never shows; its frame is a stub, one quad filling the view. The server hands an upgraded connection to the app as two byte queues (control/Link), so the UI thread reads and writes once a frame and no thread is needed per view. A view the client closes, or that goes with a dropped connection, closes its window. fizzy.remote.views lists them. Part of fizzyedit/work#40 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016mgAaDN3ndpHLtmoA72ZLQ
Fixes from reviewing the diff: a double free of the link when accepting it ran out of memory; a close that could be missed by the writer task; the link read after the app could free it; a slow peer that could not be cut off (the link now shuts its socket down on overflow, and the stop path shuts connections down before waiting on them); an unbounded inbox. Input past the queue's cap now drops motion, never a press, a release or a key-up, and a zero-sized resize is ignored. Part of fizzyedit/work#40 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016mgAaDN3ndpHLtmoA72ZLQ
The control link's backlog (8 MiB) sat below the protocol's 32 MiB frame cap, so a legal large frame dropped the connection; it is now 64 MiB, asserted at comptime against the cap. A view's queued text is capped at 1 MiB, a connection holds at most 64 views, and the service at 8 connections (a ninth gets 503). A duplicate view id, which the protocol layer already ends the stream for, is guarded in the session without a view_closed that would make the client forget the open view. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
foxnne
force-pushed
the
app/remote-view-host
branch
from
October 21, 2026 22:16
c190b17 to
8e972c9
Compare
A session that dies is closed, and if its peer never reads the bye the writer stays blocked: Link.reapStuck turns that close into an abort after 2 s, from the session's pump and from closeAll (which no longer spins forever). Tests: 503 for the ninth client on the socket, and a stuck writer whose slot frees. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
foxnne
force-pushed
the
app/remote-view-host
branch
from
October 21, 2026 22:17
8e972c9 to
4fbe091
Compare
routes pumps ask for a frame while any remote link is closing, so the 2 s grace ends in an abort even when the app is idle. closeAll keeps waiting when its sleep is cancelled instead of freeing a session whose tasks may still run. The 503 test hands its status over with an atomic flag. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of fizzyedit/work#40 (EMBEDDED_EDITOR_PLAN step 3, fizzyedit/work#32)
What changes
A remote client (an adapter in Blender, Unreal, …) can now connect to the control socket,
GET /remotewithUpgrade: fizzy-remote-view/1, and speak thesdk/remoteprotocol: open a view, send pointer/key/text input, ask for frames and get them. Without the upgrade header the answer is 426, with another method 405. The socket stays 0600 and same-user.app/control/Link.zig+Server.zig: an upgraded connection becomes two byte queues. A reader and a writer task per connection do the waiting; the UI thread drains and fills the queues once per frame (Service.pump). No thread per view, and the UI thread never blocks.app/remote/RemoteViewHost.zig: aViewHostthat the OS never shows.ViewHost's vtable is unchanged. Input waits in the host as dvui events untilinject(win); keys and text only while the client says the view is focused. A view the client closes, or one that goes with a dropped connection, is dropped from its session.app/remote/Session.zig/Service.zig: one conversation per client overEndpoint, and the registry.fizzy.remote.views(internal) lists the open views.app/remote/encoder.zig: the stub, one quad filling the view.app/remote/keys.zig:Key.codeis read as a USB HID usage (the numbering SDL scancodes use). This is a decision I made, not one the plan states; please check it.docs/CONTROL.md: the route andfizzy.remote.views.SDK impact
(
sdk_versionuntouched;sdk/remoteis only imported by the app module, inbuild/sdk.zig.)Verified
Tests in
app/remote/tests.zig(fizzy-app-tests), among them a client on the real socket: create a view, send motion/click/key/text, ask a frame, drop the connection with a frame request in flight (the session and its view go, fizzy keeps running), then a second client served as before. One editor-facing body ofViewHostcalls runs against a local fake host and the remote one. Input is injected into advui.testingwindow and checked at the view's offset.Server.zighas its own tests for the upgraded byte stream.scripts/check-fmt.sh,build,build test,build test-integration(92/92 steps),build check-web,build test-sdk-version,build lint,build check-tests-reachedcheck-webbuilds; the control server is native onlyFollow-ups
TODO(seam)inService.zig, EMBEDDED_EDITOR_PLAN step 4). Until it does, input waits in the host (up to 1024 events) andpumpanswers frame requests itself with the stub. I did not wire the Editor, so remote input cannot land on the main window at the wrong origin.encoder.solidFill(TODO(seam)).Link/Serverupgrade code that has to travel with the route.jjin this cloud session (its release download is blocked and the checkout has no.jj), so this branch was committed with git.Generated by Claude Code
Limits and refusals
Service.max_sessions(8) is refused with plain HTTP503and a JSON body, never a101; an adapter must treat any non-101 as refused.sdk/remote/Client.zigalready maps a 503 toerror.Closedand any other non-101 toFizzyTooOld, so no new error was added.Link.reapStuck) 2 s later if its peer will not read the bye, so a stuck peer cannot hold a slot or hang quit.Session.pump, which could mark a session with no hello after a deadlinedead.Link.max_backlogs (inbox, outbox, and the batch the writer took), stated inService.zig.